import config from "./config.js";
import { generateRandomId } from "./utils.js";
import { addCache, getCache, clearCache } from "./cache.js";

export const originalProto = XMLHttpRequest.prototype;
export const originalOpen = XMLHttpRequest.prototype.open;
export const originalSend = XMLHttpRequest.prototype.send;

export function isSupportSendBeacon() {
    return 'sendBeacon' in navigator;
}

export function report(data) {
    if(!config.url) {
        console.error('请设置上传url地址');
        return;
    }
    const reportData = JSON.stringify({
        id: generateRandomId(),
        data,
    });
    // 上报数据，使用图片的方式
    if(config.isImageUpload) {
        imgRequest(reportData);
    } else {
        // 优先使用 sendBeacon
        if(window.navigator.sendBeacon) {
            return beaconRequest(reportData);
        } else {
            xhrRequest(reportData);
        }
    }
}

// 批量上报数据
export function lazyReportBatch(data) {
    addCache(data);
    const dataCache = getCache();
    console.error('dataCache',dataCache);
    if(dataCache.length && dataCache.length >= config.batchSize) {
        report(dataCache);
        clearCache();
    }
}

// 图片发送数据
export function imgRequest(data) {
    const img = new Image();
    // http://127.0.0.1:8080/api?data=encodeURIComponent(data)
    // encodeURIComponent() 函数可把字符串作为 URI 组件进行编码。
    img.src = `${config.url}?data=${encodeURIComponent(JSON.stringify(data))}`;
}

// 普通ajax发送请求数据
export function xhrRequest(data) {
    // https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestIdleCallback
    // window.requestIdleCallback() 方法插入一个函数，这个函数将在浏览器空闲时期被调用。
    if(window.requestIdleCallback) {
        window.requestIdleCallback(
            // 一个在事件循环空闲时即将被调用的函数的引用。函数会接收到一个名为 IdleDeadline 的参数，这个参数可以获取当前空闲时间以及回调是否在超时时间前已经执行的状态。
            () => {
                const xhr = new XMLHttpRequest();
                originalOpen.call(xhr,"post",config.url);
                originalSend.call(xhr,JSON.stringify(data));
            },
            {timeout:3000} // 如果指定了 timeout，并且有一个正值，而回调在 timeout 毫秒过后还没有被调用，那么回调任务将放入事件循环中排队，
        )
    } else {
        setTimeout(() => {
            const xhr = new XMLHttpRequest();
            originalOpen.call(xhr,"post",config.url);
            originalSend.call(xhr,JSON.stringify(data));
        })
    }
}

// sendBeacon发送请求数据
// https://developer.mozilla.org/zh-CN/docs/Web/API/Navigator/sendBeacon
// 为了把尽量多的页面信息传到服务器，很多分析工具需要在页面生命周期尽量晚到时候向服务器发送分析数据，理想情况是通过浏览器unload发送请求，这个事件表示用户要离开当前页面，不会再生成别的有用信息了
// 但是unload事件不适合发送请求，因为unload事件处理程序中的异步请求会被浏览器取消，sendBeacon就是为了解决这个问题而生的
// sendBeacon()在任何时候都可以使用，调用之后浏览器会把请求添加到一个内部请求的队列，浏览器会主动发送队列请求
// 浏览器保证在原始页面关闭的情况下也会发送请求
// 接受url和一个数据有效载荷参数，并发送一个post请求
// 返回布尔值，表明是否成功进入最终要发送的任务队列
export function beaconRequest(data) {
    if(window.requestIdleCallback) {
        window.requestIdleCallback(
            () => {
                window.navigator.sendBeacon(config.url, data);
            },
            {timeout:3000}
        )
    } else {
        setTimeout(() => {
            window.navigator.sendBeacon(config.url, data);
        })
    }
}